package org.xx.armory.rpc.routing;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.regex.Pattern.CASE_INSENSITIVE;
import static java.util.regex.Pattern.COMMENTS;
import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.UNICODE_CASE;
import static java.util.regex.Pattern.UNICODE_CHARACTER_CLASS;

/**
 * 路由标记中的占位符。
 *
 * @author Haart
 */
final class RoutePlaceHolder
        extends RouteToken {
    /**
     * 允许匹配的URL内容，可以是除了斜杠和反斜杠之外的其它任何字符。
     */
    private static final String DEFAULT_RESTRICTION_PATTERN = "[^/\\\\]+";
    private static final int RESTRICTION_PATTERN_OPTIONS = CASE_INSENSITIVE | DOTALL | COMMENTS | UNICODE_CHARACTER_CLASS | UNICODE_CASE;

    private final String _default;
    private final Pattern restriction;

    /**
     * 构造路由标记中的占位符。
     *
     * @param name
     *         占位符的名字。
     * @param _default
     *         占位符的默认值，{@code null}表示没有默认值，该占位符必填。
     * @param restriction
     *         占位符的约束表达式，{@code null}表示使用默认约束。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符。
     * @see #DEFAULT_RESTRICTION_PATTERN
     */
    public RoutePlaceHolder(
            String name,
            String _default,
            String restriction
    ) {
        super(name, RouteTokenType.PLACEHOLDER);

        this._default = _default;
        restriction = restriction != null ? restriction : DEFAULT_RESTRICTION_PATTERN;
        this.restriction = Pattern.compile(restriction, RESTRICTION_PATTERN_OPTIONS);
    }

    /**
     * 获取占位符的约束表达式。
     *
     * @return 占位符的约束表达式。
     */
    public String getPattern() {
        return restriction.pattern();
    }

    /**
     * 获取占位符的默认值。
     *
     * @return 占位符的默认值。
     */
    public String getDefault() {
        return this._default;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    final String match(
            String url,
            int pos
    ) {
        Matcher mo = this.restriction.matcher(url);
        return mo.find(pos) ? mo.group(0) : null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return Objects.hash(this.getName(), this.getDefault(), this.getPattern());

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (obj.getClass() != this.getClass()) {
            return false;
        }

        final RoutePlaceHolder other = (RoutePlaceHolder) obj;
        return Objects.equals(this.getName(), other.getName())
                && Objects.equals(this.getDefault(), this.getDefault())
                && Objects.equals(this.getPattern(), this.getPattern());
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        return this.getName() + ": " + this.getPattern();
    }
}
